package com.otitan.la.forest.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.otitan.la.forest.system.constant.StaticConstant;
import com.otitan.la.forest.system.dto.DicDTO;
import com.otitan.la.forest.system.entity.DicEntity;
import com.otitan.la.forest.system.entity.DicTypeEntity;
import com.otitan.la.forest.system.mapper.DicMapper;
import com.otitan.la.forest.system.service.DicService;
import com.otitan.la.forest.system.service.DicTypeService;
import com.otitan.la.forest.system.vo.DicVO;
import com.otitan.webapp.framework.basepro.exception.code.BaseResponseCode;
import com.otitan.webapp.framework.basepro.model.DataResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DicServiceImpl extends ServiceImpl<DicMapper, DicEntity> implements DicService {

    @Value("${redis.key-prefix}")
    private String redisKeyPrefix;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private DicTypeService dicTypeService;
    @Resource
    private DicMapper dicMapper;

    @Transactional
    @Override
    public DataResult add(DicEntity dic, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return DataResult.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        // 判断字典类型是否存在
        boolean exist = dicTypeService.existDicType(dic.getDicTypeCode());
        if (!exist) {
            return DataResult.fail("字典类型不存在");
        }

        // 字典不能重复
        LambdaQueryWrapper<DicEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DicEntity::getDicTypeCode, dic.getDicTypeCode());
        queryWrapper.eq(DicEntity::getDicCode, dic.getDicCode());
        queryWrapper.or(wrapper -> {
            wrapper.eq(DicEntity::getDicTypeCode, dic.getDicTypeCode());
            wrapper.eq(DicEntity::getDicName, dic.getDicName());
        });

        int count = this.count(queryWrapper);
        if (count > 0) {
            return DataResult.fail("字典已存在");
        }
        boolean isSuccess = this.save(dic);
        //save至redis中
        String key = getKey(dic);
        redisTemplate.opsForHash().put(key, dic.getDicCode(), dic.getDicName());
        return isSuccess ? DataResult.success() : DataResult.fail(BaseResponseCode.DATA_NOT_EXIST.getMsg());
    }

    @Transactional
    @Override
    public DataResult batchDelete(List<String> ids) {
        LambdaQueryWrapper<DicEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(DicEntity::getId, ids);
        List<DicEntity> dicEntityList = this.list(queryWrapper);
        dicEntityList.forEach(dic -> {
            String key = getKey(dic);
            redisTemplate.opsForHash().delete(key, dic.getDicCode());
        });
        boolean isSuccess = this.removeByIds(ids);
        log.debug("\n>>>>>>>>> 【删除字典表】 <<<<<<<<<\n操作结果：{}，ids：{}\n>>>>>>>>> ---- <<<<<<<<<", isSuccess, ids);
        return DataResult.success();
    }

    @Transactional
    @Override
    public DataResult editor(DicEntity dic, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return DataResult.fail(bindingResult.getFieldError().getDefaultMessage());
        }

        //判断所修改的字典类型是否存在
        LambdaQueryWrapper<DicTypeEntity> query = Wrappers.lambdaQuery();
        query.eq(DicTypeEntity::getDicTypeCode, dic.getDicCode());
        int num = dicTypeService.count(query);
        if (num < 0) {
            DataResult.fail("所修改字典类型不存在！请先添加该字典类型");
        }

        // 字典不能重复
        LambdaQueryWrapper<DicEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.and(wrapper -> {
            wrapper.ne(DicEntity::getId, dic.getId());
            wrapper.eq(DicEntity::getDicTypeCode, dic.getDicTypeCode());
            wrapper.eq(DicEntity::getDicCode, dic.getDicCode());
        }).or(wrapper -> {
            wrapper.ne(DicEntity::getId, dic.getId());
            wrapper.eq(DicEntity::getDicTypeCode, dic.getDicTypeCode());
            wrapper.eq(DicEntity::getDicName, dic.getDicName());
        });
        int count = this.count(queryWrapper);
        if (count > 0) {
            return DataResult.fail("字典已存在");
        }

        DicEntity dicEntity = this.getById(dic.getId());
        String key = getKey(dic);
        String keys = getKey(dicEntity);
        redisTemplate.opsForHash().delete(key, dicEntity.getDicTypeCode());
        redisTemplate.opsForHash().delete(keys, dicEntity.getDicTypeCode());
        redisTemplate.opsForHash().put(key, dic.getDicCode(), dic.getDicName());

        boolean isSuccess = this.updateById(dic);
        return isSuccess ? DataResult.success() : DataResult.fail(BaseResponseCode.DATA_NOT_EXIST.getMsg());
    }

    private String getKey(DicEntity dic) {
        return redisKeyPrefix + StaticConstant.DICTIONARY + dic.getDicTypeCode();
    }

    @Override
    public DataResult findPageData(long page, long size, DicDTO dic) {
        Page<DicVO> pagePlug = new Page<>(page, size);
        pagePlug.setRecords(this.baseMapper.findPageData(dic, pagePlug));
        return DataResult.success(pagePlug);
    }

    @Override
    public DataResult findOne(String id) {
        return DataResult.success(this.getById(id));
    }

    @Override
    public DataResult getOptions(String dicTypeCodes) {
        String[] split = dicTypeCodes.split(",|，");
        LambdaQueryWrapper<DicEntity> queryWrapper = Wrappers.lambdaQuery();
        //查询条件示例
        queryWrapper.in(DicEntity::getDicTypeCode, split);
        queryWrapper.orderByAsc(DicEntity::getOrderNo);
        List<DicEntity> list = this.list(queryWrapper);
        Map<String, List<DicEntity>> listMap = list.stream().collect(Collectors.groupingBy(DicEntity::getDicTypeCode));
        Map<String, List<DicEntity>> resMap = new HashMap<>();
        for (Map.Entry<String, List<DicEntity>> entry : listMap.entrySet()) {
            resMap.put(entry.getKey(), entry.getValue());
        }
        return DataResult.success(resMap);
    }

    @Override
    public void saveToRedis() {
        List<DicDTO> allDic = dicMapper.findAllDic();
        Map<String, List<DicDTO>> collect = allDic.stream()
                .collect(Collectors.groupingBy(DicDTO::getDicTypeCode));

        // 先删除Redis中的字典
        Set keys =redisTemplate.keys(redisKeyPrefix + StaticConstant.DICTIONARY +"*");
        redisTemplate.delete(keys);

        Map<String, String> map = null;
        for (Map.Entry<String, List<DicDTO>> entry : collect.entrySet()) {
            String key = entry.getKey();
            List<DicDTO> value = entry.getValue();
            map = new HashMap<>();
            for (DicDTO dto : value) {
                map.put(dto.getDicCode(), dto.getDicName());
            }
            redisTemplate.opsForHash().putAll(redisKeyPrefix + StaticConstant.DICTIONARY + key, map);
        }
    }

    @Override
    public String getDicName(String typeKey, String key) {
        if (key == null) {
            return null;
        }
        Object dicName = redisTemplate.opsForHash().get(redisKeyPrefix + StaticConstant.DICTIONARY + typeKey, key);
        return dicName == null ? null : dicName.toString();
    }

}